﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using SLogo.Compile;

namespace SLogo.Helper
{
    /// <summary>
    /// 编译帮助类
    /// </summary>
    class CompileHelper
    {
        /// <summary>
        /// 编译预处理，去除注释和多余的空白符，合并连续的加减和非，转换为全部小写
        /// </summary>
        /// <param name="sourceCode">需要预处理的字符串</param>
        public static String PreCompile(String sourceCode)
        {
            //转为UTF8
            sourceCode = StringHelper.AnsiToUtf8(sourceCode);
            //合并连续的+-和!号
            Combine(ref sourceCode);
            //去除注释和多余的空白符，并转换字符串外的大写为小写
            Delete(ref sourceCode);
            sourceCode = Regex.Replace(sourceCode, "[ |\\t]{0,}\n[ |\\t]{0,}", "\n");
            //读出来的换行是\r\n，需要替换为\n
            sourceCode = sourceCode.Replace("\r\n", "\n");
            return sourceCode;
        }

        #region 这些代码仅仅是为了测试
        public static void PrintIntermediateCode()
        {
            int l = 0;
            foreach(IntermediateCode i in SyntaxAndSemanticAnalysis.IntermediateCodeList)
            {
                Console.Write(l++ + ":  ");
                PrintAIcode(i);
            }
            Console.WriteLine();
        }

        private static void PrintAIcode(IntermediateCode i)
        {
            Console.Write(i.Operator + ",");
            if (i.Arguments != null)
            {
                foreach (Agument a in i.Arguments)
                {
                    switch (a.TheType)
                    {
                        case Agument.ArgumentType.Number:
                            Console.Write(a.NumberValue + ",");
                            break;
                        case Agument.ArgumentType.String:
                            Console.Write(a.StringValue + ",");
                            break;
                        default:
                            if (a.VariableValue.TheType == Variable.VariableType.String)
                            {
                                Console.Write(a.VariableValue.StringValue + ",");
                            }
                            else
                            {
                                Console.Write(a.VariableValue.NumberValue + ",");
                            }
                            break;
                    }
                }
            }
            if (i.Result != null && i.Result.TheType == Variable.VariableType.String)
            {
                Console.Write(i.Result.StringValue + ",");
            }
            else if(i.Result != null)
            {
                Console.Write(i.Result.NumberValue + "，");
            }
            Console.WriteLine(i.FileName + "," + i.Line);
        }

        public static void PrintCusPro()
        {
            int l = 0;
            foreach(CustomProcess c in SyntaxAndSemanticAnalysis.CustomProcessList)
            {
                Console.Write(c.Name + ",");
                if (c.Arguments != null)
                {
                    foreach (Variable v in c.Arguments)
                    {
                        if (v.TheType == Variable.VariableType.String)
                        {
                            Console.Write(v.StringValue + ",");
                        }
                        else
                        {
                            Console.Write(v.NumberValue + "，");
                        }
                    }
                }
                Console.WriteLine();
                foreach (IntermediateCode i in c.CodeBlock)
                {
                    Console.Write(l++ + ":  ");
                    PrintAIcode(i);
                }
                Console.WriteLine("\n");
            }
        }
        #endregion

        #region 编译预处理所需要的私有方法
        //删除注释和多余的空白，并转换字符串外的大写为小写
        private static void Delete(ref String sourceCode)
        {
            int quotNum = 0;//一行中双引号的数目
            for (int i = 0; i < sourceCode.Length; i++)
            {
                if (sourceCode[i] == '"')//引号计数
                {
                    quotNum++;
                    continue;
                }
                if (sourceCode[i] == '\n')//引号计数器清零
                {
                    quotNum = 0;
                    continue;
                }
                if (sourceCode[i] == ';' && quotNum % 2 == 0)//如果分号在双引号对外边
                {
                    int enterPosition = sourceCode.IndexOf('\n', i);
                    int length = enterPosition == -1 ? sourceCode.Length - i : enterPosition - i;//处理注释在最后一行的情况
                    sourceCode = sourceCode.Remove(i, length);
                    quotNum = 0;
                    continue;
                }
                if ((sourceCode[i] == ' ' || sourceCode[i] == '\t') && quotNum % 2 == 0)//如果空白在双引号对外边
                {
                    sourceCode = sourceCode.Remove(i, 1).Insert(i, " ");//第一个替换为空格
                    i++;
                    while (i < sourceCode.Length &&(sourceCode[i] == ' ' || sourceCode[i] == '\t'))//后边的连续空白符删除
                    {
                        sourceCode = sourceCode.Remove(i, 1);
                        if (i == sourceCode.Length)
                        {
                            break;
                        }
                    }
                    i--;
                    continue;
                }
                if(sourceCode[i] >= 'A' && sourceCode[i] <= 'Z' && quotNum % 2 == 0)//大小写转换，转换双引号外面的
                {
                    char tmp = (char)(sourceCode[i] + 32);//转为小写字母
                    sourceCode = sourceCode.Remove(i, 1).Insert(i, tmp.ToString());
                }
            }
        }
        //合并连续的加减和非
        private static void Combine(ref String sourceCode)
        {
            int inBlock = 0; //方括号的层数
            for (int i = 0; i < sourceCode.Length; i++)
            {
                if (sourceCode[i] == '[')
                {
                    inBlock++;
                    continue;
                }
                if (sourceCode[i] == ']')
                {
                    inBlock = inBlock == 0 ? 0 : inBlock - 1;
                    continue;
                }
                if (sourceCode[i] == '+' || sourceCode[i] == '-') //化简+-号
                {
                    if (inBlock == 0) //如果在方括号外边
                    {
                        int position = i;
                        i++;
                        while (i < sourceCode.Length &&(sourceCode[i] == '+' || sourceCode[i] == '-' ||
                               sourceCode[i] == ' ' || sourceCode[i] == '\t')) //如果是连续的+-
                        {
                            if (sourceCode[i] == '-') //如果是减号，则需要反号
                            {
                                String tmp = sourceCode[position] == '-' ? "+" : "-"; //反号
                                sourceCode = sourceCode.Remove(position, 1).Insert(position, tmp); //替换
                                sourceCode = sourceCode.Remove(i, 1);//删除多余的-
                                continue;
                            }
                            if (sourceCode[i] == '+')
                            {
                                sourceCode = sourceCode.Remove(i, 1);//删除多余的+
                                continue;
                            }
                            i++;
                            if (i == sourceCode.Length)
                            {
                                break;
                            }
                        }
                        i--;
                    }
                    else //方括号里边换行视为空格
                    {
                        int position = i;
                        i++;
                        while (i < sourceCode.Length &&(sourceCode[i] == '+' || sourceCode[i] == '-' ||
                               sourceCode[i] == ' ' || sourceCode[i] == '\t' || sourceCode[i] == '\n')) //如果是连续的+-
                        {
                            if (sourceCode[i] == '-') //如果是减号，则需要反号
                            {
                                String tmp = sourceCode[position] == '-' ? "+" : "-"; //反号
                                sourceCode = sourceCode.Remove(position, 1).Insert(position, tmp); //替换
                                sourceCode = sourceCode.Remove(i, 1);//删除多余的-
                                continue;
                            }
                            if (sourceCode[i] == '+')
                            {
                                sourceCode = sourceCode.Remove(i, 1);//删除多余的+
                                continue;
                            }
                            i++;
                            if (i == sourceCode.Length)
                            {
                                break;
                            }
                        }
                        i--;
                    }
                    continue;
                }
                if (sourceCode[i] == '!') //化简非
                {
                    if (inBlock == 0) //如果在方括号外边
                    {
                        int position = i;
                        i++;
                        int numNot = 1;
                        while (i < sourceCode.Length &&(sourceCode[i] == '!' || sourceCode[i] == ' ' || sourceCode[i] == '\t')) //如果是连续的+-
                        {
                            if (sourceCode[i] == '!')
                            {
                                position = numNot % 2 == 0 ? i : position;
                                numNot++;
                                if (numNot % 2 == 0) //如果是连续的两个!
                                {
                                    sourceCode = sourceCode.Remove(position, 1).Remove(i - 1, 1);
                                    i--;
                                    continue;
                                }
                            }
                            i++;
                            if (i == sourceCode.Length)
                            {
                                break;
                            }
                        }
                        i--;
                    }
                    else //方括号里边换行视为空格
                    {
                        int position = i;
                        i++;
                        int numNot = 1;
                        while (i < sourceCode.Length &&(sourceCode[i] == '!' || sourceCode[i] == ' ' ||
                               sourceCode[i] == '\t' || sourceCode[i] == '\n')) //如果是连续的+-
                        {
                            if (sourceCode[i] == '!')
                            {
                                position = numNot % 2 == 0 ? i : position;
                                numNot++;
                                if (numNot % 2 == 0) //如果是连续的两个!
                                {
                                    sourceCode = sourceCode.Remove(position, 1).Remove(i - 1, 1);
                                    i--;
                                    continue;
                                }
                            }
                            i++;
                            if (i == sourceCode.Length)
                            {
                                break;
                            }
                        }
                        i--;
                    }
                }
            }
        }

        #endregion
    }
}
